<template>
  <div class="rich-text-editor">
    <textarea :id="elId"></textarea>
    <div v-if="!ready" class="text-sm text-gray-500">编辑器加载中...</div>
  </div>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount, watch, nextTick } from 'vue'

// Global loader to ensure TinyMCE script loads once
let tinymceReadyPromise = null
const loadTinymceOnce = (baseUrl) => {
  if (typeof window !== 'undefined' && window.tinymce) return Promise.resolve()
  if (tinymceReadyPromise) return tinymceReadyPromise
  tinymceReadyPromise = new Promise((resolve, reject) => {
    if (typeof window === 'undefined') return resolve()
    const s = document.createElement('script')
    const url = (baseUrl || 'https://cdn.jsdelivr.net/npm/tinymce@6.8.3') + '/tinymce.min.js'
    s.src = url
    s.onload = () => resolve()
    s.onerror = () => reject(new Error('TinyMCE load failed'))
    document.head.appendChild(s)
  })
  return tinymceReadyPromise
}

const props = defineProps({
  modelValue: { type: String, default: '' },
  height: { type: Number, default: 320 },
  menubar: { type: Boolean, default: false },
  plugins: { type: String, default: 'lists table link advlist charmap fullscreen codesample wordcount' },
  toolbar: { type: String, default: 'fullscreen | undo redo | removeformat | blocks fontsizeselect | bold italic underline strikethrough | forecolor backcolor | alignleft aligncenter alignright alignjustify | outdent indent | bullist numlist | blockquote | link table | codesample' },
  toolbarMode: { type: String, default: 'wrap' },
  language: { type: String, default: 'zh_CN' },
  useI18n: { type: Boolean, default: true },
  languageUrl: { type: String, default: '/tinymce/langs/zh_CN.js' },
  contentStyle: { type: String, default: 'table, td, th { user-select: auto !important; -webkit-user-select: auto !important; } pre, code { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; }' },
  blockFormats: { type: String, default: '段落=p; 标题 1=h1; 标题 2=h2; 标题 3=h3; 标题 4=h4; 标题 5=h5; 标题 6=h6' },
  baseUrl: { type: String, default: 'https://cdn.jsdelivr.net/npm/tinymce@6.8.3' },
  suffix: { type: String, default: '.min' },
  initOptions: { type: Object, default: () => ({}) },
  editorId: { type: String, default: () => `rte-${Math.random().toString(36).slice(2, 10)}-${Date.now().toString(36)}` }
})

const emit = defineEmits(['update:modelValue', 'ready', 'change'])

const elId = ref(props.editorId)
const ready = ref(false)
let editor = null
let settingContent = false
let pendingContent = ref(props.modelValue)

const codesampleLanguages = [
  {text:'Plain',value:'none'},{text:'JavaScript',value:'javascript'},{text:'TypeScript',value:'typescript'},{text:'JSX',value:'jsx'},{text:'TSX',value:'tsx'},
  {text:'HTML',value:'markup'},{text:'CSS',value:'css'},{text:'JSON',value:'json'},{text:'YAML',value:'yaml'},{text:'Markdown',value:'markdown'},
  {text:'Java',value:'java'},{text:'Kotlin',value:'kotlin'},{text:'Swift',value:'swift'},{text:'Python',value:'python'},{text:'Go',value:'go'},
  {text:'Rust',value:'rust'},{text:'C',value:'c'},{text:'C++',value:'cpp'},{text:'C#',value:'csharp'},{text:'PHP',value:'php'},{text:'Ruby',value:'ruby'},
  {text:'Dart',value:'dart'},{text:'Bash',value:'bash'},{text:'PowerShell',value:'powershell'},{text:'SQL',value:'sql'},{text:'XML',value:'xml'}
]

const setTinymceBase = () => {
  try {
    if (typeof window !== 'undefined' && window.tinymce) {
      window.tinymce.baseURL = props.baseUrl
      window.tinymce.suffix = props.suffix
    }
  } catch {}
}

onMounted(async () => {
  await loadTinymceOnce(props.baseUrl)
  setTinymceBase()
  if (!window.tinymce) return
  
  try { 
    const oldEditor = window.tinymce.get(elId.value)
    if (oldEditor) oldEditor.remove() 
  } catch (e) {
    console.warn('Failed to remove existing editor instance:', e)
  }

  const options = {
    selector: `#${elId.value}`,
    height: props.height,
    menubar: props.menubar,
    plugins: props.plugins,
    toolbar: props.toolbar,
    toolbar_mode: 'wrap',
    branding: false,
    content_style: props.contentStyle,
    block_formats: props.blockFormats,
    base_url: props.baseUrl,
    suffix: props.suffix,
    codesample_languages: codesampleLanguages,
    setup: (ed) => {
      editor = ed
      ed.on('init', () => {
        ready.value = true
        // 使用nextTick确保DOM更新完成
        nextTick(() => {
          if (pendingContent.value) {
            settingContent = true
            ed.setContent(pendingContent.value, { format: 'raw' })
            settingContent = false
            pendingContent.value = null
            // 清空撤销栈
            ed.undoManager.clear()
            // 强制重绘
            setTimeout(() => {
              try {
                if (ed.plugins?.codesample?.updateCodeBlocks) {
                  ed.plugins.codesample.updateCodeBlocks()
                }
                ed.nodeChanged()
              } catch (e) {
                console.log('Failed to update code blocks:', e)
                ed.nodeChanged()
              }
            }, 100)
          }
          emit('ready', ed)
        })
      })
      
      let debounceTimer = null
      const propagate = () => {
        if (settingContent) return
        if (debounceTimer) clearTimeout(debounceTimer)
        debounceTimer = setTimeout(() => {
          try {
            const html = ed.getContent()
            emit('update:modelValue', html)
            emit('change', html)
          } catch (e) {
            console.error('Error updating content:', e)
          }
        }, 300)
      }
      
      ed.on('change keyup undo redo input SetContent', propagate)
      
      // Fix initial word count
      ed.on('init', () => {
        setTimeout(() => {
          ed.nodeChanged()
          ed.fire('SetContent')
        }, 500)
        setTimeout(() => {
          ed.nodeChanged()
        }, 1500)
      })
    },
    ...props.initOptions,
  }
  
  if (props.useI18n && props.language) {
    options.language = props.language
    options.language_url = props.languageUrl
  }
  
  window.tinymce.init(options)
  
  // Fallback: if init doesn't fire for some reason (e.g. already initialized on this ID?), force ready
  setTimeout(() => {
    if (!ready.value && window.tinymce && window.tinymce.get(elId.value)) {
      ready.value = true
    }
  }, 1000)
})

watch(() => props.modelValue, (newVal) => {
  if (!editor || settingContent) return
  const currentContent = editor.getContent() || ''
  if (newVal !== currentContent) {
    settingContent = true
    editor.setContent(newVal || '', { format: 'raw' })
    settingContent = false
    // 清空撤销栈
    nextTick(() => {
      editor.undoManager.clear()
      editor.nodeChanged()
    })
  }
}, { immediate: true })

onBeforeUnmount(() => {
  if (window.tinymce) {
    try {
      const inst = window.tinymce.get(elId.value)
      if (inst) {
        // 保存内容
        const content = inst.getContent()
        if (content) {
          emit('update:modelValue', content)
        }
        // 移除编辑器
        inst.remove()
      }
    } catch (e) {
      console.warn('Error removing editor instance:', e)
    }
  }
})
</script>

<style>
.rich-text-editor {
  position: relative;
}
.rich-text-editor textarea {
  visibility: hidden;
  height: 0;
  width: 0;
  position: absolute;
}
</style>
